package com.example.base_model.socket

import android.util.Log
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ViewUtils
import com.example.base_model.bean.WebSocketBean
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okio.ByteString
import java.io.IOException
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean

/**
 * @Author jiangKunKun
 * @CreateDate 2025/9/17
 * @Description WebSocket客户端，用于建立、管理和维护与WebSocket服务器的连接。
 * @SpittingGrooves
 */
object WebSocketClient {
    // 用于日志记录的TAG
    private const val TAG = "WebSocketClient"

    /**
     * Moshi实例 - 单例模式，避免重复创建，用于JSON的序列化和反序列化。
     */
    private val moshi = Moshi.Builder().build()

    /**
     * WebSocketBean<Any>的类型信息 - 用于第一层解析，将接收到的WebSocket消息初步解析为通用类型。
     */
    private val baseWebSocketType = Types.newParameterizedType(WebSocketBean::class.java, Any::class.java)

    /**
     * WebSocketBean<Any>的适配器 - 用于第一层解析，将原始JSON字符串转换为 [WebSocketBean<Any>]。
     */
    private val baseWebSocketAdapter = moshi.adapter<WebSocketBean<Any>>(baseWebSocketType)

    /**
     * 连接状态 - 使用原子类 [AtomicBoolean] 保证线程安全，表示WebSocket连接是否处于活动状态。
     */
    private val connectionState = AtomicBoolean(false)

    /**
     * WebSocket地址，根据配置（例如是否是测试环境）选择不同的URL。
     * wss://match-api.sigoran.com/dws  正式环境
     * wss://tmatch-api.sigoran.com/dws 测试环境
     */
    private val WS_URL = if (true) "wss://tmatch-api.sigoran.com/dws" else "wss://match-api.sigoran.com/dws"

    /**
     * WebSocket对象，通过 OkHttpClient 创建和管理。
     * 使用 @Volatile 保证多线程环境下对该变量的可见性。
     */
    @Volatile
    private var webSocket: WebSocket? = null

    /**
     * OkHttpClient对象基础配置，设置了ping间隔用于保持连接活跃。
     */
    private val client = OkHttpClient.Builder()
        .pingInterval(10, TimeUnit.SECONDS) // 设置ping间隔为10秒，用于发送心跳包保持连接
        .build()

    /**
     * 重连间隔时间，单位为毫秒，表示尝试重新连接WebSocket的时间间隔。
     */
    private const val RECONNECT_INTERVAL = 5000L
    /**
     * 重连次数
     */
    private var reconnectAttempts = 0

    /**
     * 重连调度器，使用 [ScheduledExecutorService] 在后台线程调度重连任务。
     */
    private val reconnectScheduler: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()

    /**
     * 连接WebSocket服务器。
     * 如果WebSocket已连接，则不执行任何操作。否则，尝试建立新的连接。
     */
    fun connect() {
        // 检查是否已经连接，避免重复连接
        if (connectionState.get()) {
            LogUtils.d(TAG, "WebSocket已连接，无需重复连接")
            return
        }

        try {
            // 获取 deviceCode (此处为空字符串，实际应用中应获取真实设备码)
            val deviceCode = ""

            // 获取 sign (此处为空字符串，实际应用中应获取真实签名)
            val sign = ""

            // 构建完整的WebSocket URL，包含deviceCode和sign参数
            val wsUrl = "$WS_URL?deviceCode=$deviceCode&sign=$sign"
            LogUtils.d("wsUrl: $wsUrl")

            // 创建 OkHttp 请求对象
            val request = Request.Builder()
                .url(wsUrl)
                .build()

            // 使用 OkHttpClient 建立 WebSocket 连接，并提供 WebSocketListener 处理事件
            webSocket = client.newWebSocket(request, object : WebSocketListener() {
                /**
                 * WebSocket 连接成功时回调。
                 */
                override fun onOpen(webSocket: WebSocket, response: Response) {
                    LogUtils.d(TAG, "webSocket连接成功")
                    // 更新连接状态为true
                    connectionState.set(true)
                }

                /**
                 * 接收到文本消息时回调。
                 */
                override fun onMessage(webSocket: WebSocket, text: String) {
                    LogUtils.d(TAG, "接收消息: $text")
                    // 数据类型格式示例:  {type: "10001",deviceCode:"HCJGA325030005",content: {不同的数据类型}}
                    try {
                        // 第一层解析：解析为 WebSocketBean<*> 获取消息类型
                        val webSocketBean = baseWebSocketAdapter.fromJson(text) ?: throw IllegalArgumentException("解析结果为空")
                        when (webSocketBean.type) {
                            1 -> { // 心跳消息
                                // 解析心跳数据，例如将data字段解析为String类型
                                val heartbeatBean = parseWebSocketData(text, String::class.java)
                                heartbeatBean?.data?.let {
                                    // 处理心跳数据，例如更新心跳时间等
                                }
                            }
                            10001, 10002, 10003 -> { // 查棚相关应答消息
                                // 解析data为具体的查棚数据类，例如将data字段解析为String类型
                                val shedDataBean = parseWebSocketData(text, String::class.java)
                                shedDataBean?.data?.let {
                                    // 处理查棚数据
                                }
                            }
                            // 可以在这里添加其他消息类型的处理逻辑
                        }
                    } catch (e: Exception) {
                        // 捕获并记录WebSocket消息解析错误
                        LogUtils.d("WS解析错误\n${e.toString()}", "内容:\n$text")
                    }
                }

                /**
                 * 接收到二进制消息时回调。
                 */
                override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                    LogUtils.d(TAG, "接收二进制消息: ${bytes.hex()}")
                    // 可以在这里处理接收到的二进制消息
                }

                /**
                 * WebSocket 即将关闭时回调。
                 */
                override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                    LogUtils.d(TAG, "WebSocket Closing: $reason")
                    connectionState.set(false) // 更新连接状态为false
                    // 连接关闭时的其他操作
                }

                /**
                 * WebSocket 连接失败或发生错误时回调。
                 */
                override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                    LogUtils.d(TAG, "WebSocket Error: ${t.message}")
                    connectionState.set(false) // 更新连接状态为false
                    // 连接失败或发生错误时尝试重连
                    // 区分异常类型
                    when (t) {
                        is IOException -> {
                            // 网络异常，尝试重连
                            reconnect()
                        }
                        else -> {
                            // 其他异常，记录日志
                            LogUtils.d(TAG, "WebSocket fatal error", t)
                        }
                    }
                }
            })
        } catch (e: Exception) {
            // 捕获并记录连接WebSocket时发生的异常
            LogUtils.d(TAG, "连接WebSocket时发生异常", e)
            connectionState.set(false) // 更新连接状态为false
            reconnect() // 连接异常时尝试重连
        }
    }

    /**
     * 解析WebSocketBean的data字段为具体类型。
     *
     * @param text 原始JSON字符串，包含完整的WebSocket消息。
     * @param dataClass data字段的目标实体类，用于指定data字段应该反序列化成的具体Java类型。
     * @return 解析后的 [WebSocketBean<T>] 对象，如果解析失败则返回 null。
     */
    private inline fun <reified T> parseWebSocketData(text: String, dataClass: Class<T>): WebSocketBean<T>? {
        return try {
            // 构建带有具体data类型的 WebSocketBean 类型
            val type = Types.newParameterizedType(WebSocketBean::class.java, dataClass)
            // 创建对应类型的 Moshi 适配器
            val adapter = moshi.adapter<WebSocketBean<T>>(type)
            // 使用适配器从JSON字符串反序列化对象
            adapter.fromJson(text)
        } catch (e: Exception) {
            // 捕获并记录Moshi解析失败的异常
            LogUtils.d("使用Moshi解析WebSocket数据失败: ${e.message}", "内容: $text")
            null
        }
    }

    /**
     * 尝试重连WebSocket。
     * 如果当前未连接且重连调度器未关闭，则在指定间隔后调度一次连接尝试。
     */
    private fun reconnect() {

        // 只有在未连接状态且重连调度器未关闭时才进行重连
        if (!connectionState.get() && !reconnectScheduler.isShutdown) {
            val delay = (RECONNECT_INTERVAL * (1L shl reconnectAttempts)).coerceAtMost(60000L)
            reconnectAttempts++

            reconnectScheduler.schedule({
                // 在主线程执行连接操作，确保UI更新或相关操作在正确线程中
                ViewUtils.runOnUiThread {
                    connect()
                    if (connectionState.get()) {
                        reconnectAttempts = 0 // 重置重连次数
                    }
                }
            }, delay, TimeUnit.MILLISECONDS)
        }
    }

    /**
     * 发送消息到WebSocket服务器。
     *
     * @param message 消息内容，以String形式发送。
     */
    fun send(message: String) {
        val ws = webSocket // 获取当前WebSocket对象，避免并发修改问题
        if (ws != null && connectionState.get()) {
            // 只有在WebSocket对象存在且连接状态为true时才发送消息
            LogUtils.d(TAG, "发送消息: $message")
            if (!ws.send(message)) {
                // 如果消息发送失败，记录日志并尝试重连
                LogUtils.d(TAG, "WebSocket发送消息失败")
                reconnect()
            }
        } else {
            // 如果WebSocket未连接，记录日志并尝试重连
            reconnect()
            LogUtils.d(TAG, "WebSocket is not connected. Unable to send message.")
        }
    }

    /**
     * 关闭WebSocket连接。
     * 发送一个正常关闭的信号给服务器，并清理相关资源。
     */
    fun disconnect() {
        webSocket?.close(1000, "Normal Closure") // 发送关闭码1000和原因"Normal Closure"
        webSocket = null // 清除WebSocket对象引用
        connectionState.set(false) // 更新连接状态为false
        // 清理 OkHttpClient 资源
        client.dispatcher.executorService.shutdown()
        // 更安全的关闭方式：关闭重连调度器，防止后续任务被执行
        reconnectScheduler.apply {
            if (!isShutdown) {
                shutdown() // 关闭调度器，阻止新任务提交并等待已提交任务完成
            }
        }
    }
}